﻿using System;
using System.IO;
using System.Text;
using MF.Networker;

namespace MF.Networker
{
    /*
     * int type
     * int length
     * byte option_one
     * byte option_two
     */
    [Serializable]
    public class Packet : MF.Networker.IPacket, IDataContainer
    {
        private bool _isUsed;
        private MemoryStream _baseStream;

        [NonSerialized]
        private BinaryReader _reader;

        [NonSerialized]
        private BinaryWriter _writer;

        [NonSerialized]
        private ISession _session;

        public PacketType Type { get; set; }

        public byte OptionOne { get; set; }

        public byte OptionTwo { get; set; }

        public Packet()
        {
            this.Initialize();
        }

        public Packet(PacketType type)
        {
            this.Initialize();
            this.Type = type;
        }

        /// <summary>
        /// 初始化对象状态方法，用于构重置读写状态
        /// </summary>
        public void Initialize()
        {
            if (this._isUsed)
            {
                this.Dispose();
            }
            else
            {
                this._isUsed = true;
            }

            this._baseStream = new MemoryStream();
            this._writer = new BinaryWriter(this._baseStream, Encoding.UTF8);
            this._reader = new BinaryReader(this._baseStream, Encoding.UTF8);
        }

        public void SendBySession()
        {
            this.Session.SendAsync(this);
        }

        private void Dispose()
        {
            this._reader.Close();
            this._writer.Close();
            this._baseStream.Dispose();
        }

        #region IPacket 成员

        public byte[] ToBinary()
        {
            byte[] data;
            using (MemoryStream baseStream = new MemoryStream())
            {
                using (BinaryWriter writer = new BinaryWriter(baseStream, Encoding.UTF8))
                {
                    writer.Write((int)this.Type);
                    writer.Write((int)this._baseStream.Length);
                    writer.Write(this.OptionOne);
                    writer.Write(this.OptionTwo);
                    this._baseStream.WriteTo(baseStream);

                    data = baseStream.ToArray();
                }
            }

            return data;
        }

        public ISession Session
        {
            get { return this._session; }
            set { this._session = value; }
        }

        #endregion

        #region Read and Write Methods

        public void ClearBody()
        {
            this._baseStream.SetLength(0);
            this.Flip();
        }

        public void Flip()
        {
            if (this._baseStream.Position == 0)
            {
                return;
            }

            this._baseStream.Seek(0, SeekOrigin.Begin);
        }

        public void WriteByte(byte b)
        {
            this._writer.Write(b);
        }

        public void WriteBytes(byte[] buff)
        {
            this._writer.Write(buff, 0, buff.Length);
        }

        public void WriteBytes(byte[] buff, int offset, int count)
        {
            this._writer.Write(buff, offset, count);
        }

        public void WriteInt16(short s)
        {
            this._writer.Write(s);
        }

        public void WriteInt32(int i)
        {
            this._writer.Write(i);
        }

        public void WriteInt64(long l)
        {
            this._writer.Write(l);
        }

        public void WriteString(string msg)
        {
            this._writer.Write(msg);
        }

        public byte ReadByte()
        {
            return this._reader.ReadByte();
        }

        public byte[] ReadBytes(int count)
        {
            return this._reader.ReadBytes(count);
        }

        public short ReadInt16()
        {
            return this._reader.ReadInt16();
        }

        public int ReadInt32()
        {
            return this._reader.ReadInt32();
        }

        public long ReadInt64()
        {
            return this._reader.ReadInt64();
        }

        public string ReadString()
        {
            return this._reader.ReadString();
        }

        #endregion

        #region IDataContainer 成员

        public void SetRelationData<T>(T data)
        {
            if (this.Session != null)
            {
                this.Session.SetRelationData<T>(data);
            }
        }

        public T GetRelationData<T>()
        {
            if (this.Session != null)
            {
                return this.Session.GetRelationData<T>();
            }

            return default(T);
        }

        #endregion
    }
}
